
#ifndef _IVORONOISIMPLEXSOLVER_H_
#define _IVORONOISIMPLEXSOLVER_H_

#include <BShape>

using namespace BWE;

struct SimplexClosestResult
{
	BVector m_closestPointOnSimplex;
	bool usedVertex[4];
	BReal m_barycentricCoords[4];
	bool m_degenerate;

	void reset()
	{
		m_degenerate = false;
		setBarycentricCoordinates();
		usedVertex[0] = false;
		usedVertex[1] = false;
		usedVertex[2] = false;
		usedVertex[3] = false;
	}
	bool isValid()
	{
		bool valid = (m_barycentricCoords[0] >= BReal(0.)) &&
			(m_barycentricCoords[1] >= BReal(0.)) &&
			(m_barycentricCoords[2] >= BReal(0.)) &&
			(m_barycentricCoords[3] >= BReal(0.));

		return valid;
	}
	void setBarycentricCoordinates(BReal a = BReal(0.), BReal b = BReal(0.), BReal c = BReal(0.), BReal d = BReal(0.))
	{
		m_barycentricCoords[0] = a;
		m_barycentricCoords[1] = b;
		m_barycentricCoords[2] = c;
		m_barycentricCoords[3] = d;
	}
};

class IVoronoiSimplexSolver
{
public:
	int m_numVertices;

	BVector m_simplexVectorW[5];
	BVector m_simplexPointsP[5];
	BVector m_simplexPointsQ[5];

	BVector m_cachedP1;
	BVector m_cachedP2;
	BVector m_cachedV;
	BVector m_lastW;

	BReal m_equalVertexThreshold;
	bool m_cachedValidClosest;

	SimplexClosestResult m_cachedBC;

	bool m_needsUpdate;

public:
	IVoronoiSimplexSolver();

	void removeVertex(int index);
	void reduceVertices();
	bool updateClosestVectorAndPoints();

	bool closestPtPointTetrahedron(const BVector& p, const BVector& a, const BVector& b, const BVector& c, const BVector& d, SimplexClosestResult& finalResult);
	int pointOutsideOfPlane(const BVector& p, const BVector& a, const BVector& b, const BVector& c, const BVector& d);
	bool closestPtPointTriangle(const BVector& p, const BVector& a, const BVector& b, const BVector& c, SimplexClosestResult& result);

	void reset();

	void addVertex(const BVector& w, const BVector& p, const BVector& q);

	bool closest(BVector & v);

	BReal maxVertex();

	bool fullSimplex() const
	{
		return (m_numVertices == 4);
	}

	int getSimplex(BVector * pBuf, BVector * qBuf, BVector * yBuf) const;

	bool inSimplex(const BVector& w);

	void backup_closest(BVector & v);

	bool emptySimplex() const;

	void compute_points(BVector & p1, BVector & p2);

	int numVertices() const
	{
		return m_numVertices;
	}
};

#endif
